<template>
  <FullscreenSpin :loading="loading" tip="正在生成..." />
</template>

<script lang="ts" setup>
import { useProposalStore, useSlidesStore } from '@/store'
import { ref, onMounted, onBeforeUnmount } from 'vue'
import {
  genDefaultScoreLayout,
  getScoreFixedKey,
} from '@/mocks/customElement/score'
import {
  genDefaultSystemLayout,
  getSystemFixedKey,
} from '@/mocks/customElement/system'
import {
  genDefaultEquipLayout,
  getEquipFixedKey,
} from '@/mocks/customElement/equip'
import {
  getHeadFixedKey,
  hasProjectImageHeadSlice,
  defaultHeadPage,
} from '@/mocks/customElement/head'

import { getFootPage, getQuoteFixedKey } from '@/mocks/customElement/quote'
import { useI18n } from 'vue-i18n'
import type { Slide } from '@/types/slides'
import Message from '@/utils/message'
import useSystemFunction from '@/hooks/useSystemFunction'
import FullscreenSpin from '@/components/FullscreenSpin.vue'
import { storeToRefs } from 'pinia'
import useSlideHandler from '@/hooks/useSlideHandler'
import type {
  ProposalQuoteDetail,
  ProposalForm,
  ProposalState,
} from '@/store/proposal'

const { insertSlideByIndex } = useSystemFunction()
const { setProposalData, parsePPTXForInsetPage, parsePPTistForJson } =
  useProposalStore()
const slidesStore = useSlidesStore()
const { setTitle } = slidesStore
const { slides } = storeToRefs(slidesStore)

const { isProposalLayoutCreate, isModuleCreate } =
  storeToRefs(useProposalStore())
const { t, locale } = useI18n()

const loading = ref(false)

/**
 * ! 数据有对象有数组，旧的逻辑是对象，此处做兼容,返回一个数组
 */
const handleCompatible = (list: any): any => {
  if (Array.isArray(list)) {
    return list
  }
  else if (typeof list === 'object') {
    return [list]
  }
  return []
}

const handleReceiveMessage = async (event: MessageEvent) => {
  loading.value = true
  if (event.data?.params) {
    try {
      const params = event.data.params as ProposalState
      localStorage.setItem('token', event.data.params.token)
      locale.value = params.language
      // projectPermission 1：只读 2：编辑 3：结束邀请
      if (params.projectPermission === 1) {
        Message.warning(t('validatePermission'))
      }
      // eslint-disable-next-line no-console
      console.log('传递的数据：', params)

      // 存档数据
      setProposalData(params)
      // 设置标题
      setTitle(params.form?.name || params.form?.projectName || '空标题')

      // 处理插入页面
      await handleInsertPage(params)

      removeEmptySlide()
      slidesStore.updateSlideIndex(0)
    }
    catch (e) {
      loading.value = false
    }
  }
  loading.value = false
}

const handleInsertPage = async (params: ProposalState) => {
  const {
    softwareList,
    equipmentList,
    scoreData,
    eqptTemplate,
    softwareTemplate,
    scoreTemplate,
    insetPage,
  } = params
  // 排版布局创建时，不需要导入
  if (isProposalLayoutCreate.value || isModuleCreate.value) return

  // 导入模板 url 到页面中
  await parsePPTXForInsetPage(params.pptUrl!)
  console.log('导入完成')
  // 如果不是新增页面，不需要额外插入数据
  if (params.type !== 'add') return

  // 页面插入顺序为：系统 -> 设备
  // 评分插入顺序则按照关联关系生成
  // 因为是插入后会挤掉下一页，所以顺序和代码执行顺序相反
  try {
    if (scoreData) {
      await handleScore(params)
    }
    else {
      // 设备
      equipmentList &&
        (await handleEqpt(equipmentList, insetPage, eqptTemplate))
      // 系统
      softwareList &&
        (await handleSoft(softwareList, insetPage, softwareTemplate))

      await insertHeadPage(params)
    }

    if (params.quoteDetail) {
      await insertFootPage(params.quoteDetail)
    }
  }
  catch (e) {
    console.error(e)
  }

  window.removeEventListener('message', handleReceiveMessage)
}

const handleEqpt = async (
  equipmentList: any[],
  insetPage: number,
  eqptTemplate: any,
) => {
  const eqptMap = new Map()
  const jsonPPTXForEquipment = ref<object | object[]>()

  // 新增的时候选择了排板布局时，需要解析排版布局文件,用于选择对应模板,否则选择默认模板, id为0或不存在时走默认模板
  if (eqptTemplate?.layoutId !== 0) {
    jsonPPTXForEquipment.value = await parsePPTistForJson(
      eqptTemplate.layoutFileUrl,
    )
  }
  else {
    jsonPPTXForEquipment.value = genDefaultEquipLayout([])
  }

  if (!Array.isArray(equipmentList)) return
  for (let index = 0; index < equipmentList.length; index++) {
    const item = equipmentList[index]
    eqptMap.set(getEquipFixedKey('设备名称'), item.name || '')
    eqptMap.set(getEquipFixedKey('设备图片'), item.image)
    eqptMap.set(getEquipFixedKey('设备介绍'), item.eqptDesc || '')
    eqptMap.set(getEquipFixedKey('设备品牌'), item.brandName || '')
    eqptMap.set(getEquipFixedKey('设备编码'), item.code || '')
    eqptMap.set(getEquipFixedKey('设备型号'), item.modelName || '')
    eqptMap.set(getEquipFixedKey('性能参数'), item.perfParams || '')
    eqptMap.set(getEquipFixedKey('设备单价'), item.price || '')
    eqptMap.set(getEquipFixedKey('库存数量'), item.num || '')

    const resp = handleCompatible(jsonPPTXForEquipment.value)
    for await (const res of resp) {
      await insertSlideByIndex(res, {
        replaceDefaultImg: true,
        index: insetPage + index,
        replaceMap: eqptMap,
      })
    }
    eqptMap.clear()
  }
}

type ISoftConfig =
  | {
      relationEqpt: true
      eqptTemplate: any
    }
  | {
      relationEqpt?: false
      eqptTemplate?: any
    }
const handleSoft = async (
  softwareList: any[],
  insetPage: number,
  softwareTemplate: any,
  config?: ISoftConfig,
) => {
  const softMap = new Map()
  const jsonPPTXForSoftware = ref<object | object[]>()

  if (!Array.isArray(softwareList)) return
  for (let index = 0; index < softwareList.length; index++) {
    const item = softwareList[index]
    softMap.set(getSystemFixedKey('系统名称'), item.systemName || '')
    softMap.set(getSystemFixedKey('系统功能介绍'), item.systemDesc || '')
    softMap.set(getSystemFixedKey('过渡句'), item.pointContext || '')
    softMap.set(getSystemFixedKey('系统图片'), item.systemMainImage)
    softMap.set(getSystemFixedKey('系统描述'), item.systemContentDesc || '')
    softMap.set(getSystemFixedKey('系统价值'), item.systemWorthDesc || '')

    if (Object.prototype.hasOwnProperty.call(item, 'aiValue')) {
      softMap.set(getSystemFixedKey('智能描述'), Reflect.get(item, 'aiValue'))
    }

    // 软件模板需要动态渲染 field 和 func 字段，在遍历的时候才获取默认模板
    // 默认模板情况下，动态渲染功能字段
    if (softwareTemplate?.layoutId !== 0) {
      jsonPPTXForSoftware.value = await parsePPTistForJson(
        softwareTemplate.layoutFileUrl,
      )
    }
    else {
      jsonPPTXForSoftware.value = genDefaultSystemLayout(
        [],
        item.proposalSystemFuncList?.length || 0,
        softMap,
      )
    }

    // 确保没有数据也能够清空字段，超过20条数据不渲染
    for (let i = 0; i < 20; i++) {
      const funcData = item.proposalSystemFuncList?.[i]
      softMap.set(getSystemFixedKey('功能名称', i), funcData?.funcName || '')
      softMap.set(getSystemFixedKey('功能描述', i), funcData?.funcDesc || '')
      softMap.set(
        getSystemFixedKey('功能图片', i),
        funcData?.funcMainImage || '',
      )
      softMap.set(
        getSystemFixedKey('功能智能描述', i),
        funcData?.aiFuncDesc || '',
      )
      softMap.set(getSystemFixedKey('功能单价', i), funcData?.aiFuncDesc || '')
      softMap.set(
        getSystemFixedKey('功能智能描述', i),
        funcData?.aiFuncDesc || '',
      )
    }

    const resp = handleCompatible(jsonPPTXForSoftware.value) as [Slide]

    let runningIndex = config?.relationEqpt ? insetPage + 1 : insetPage

    // 插入系统
    await insertSlideByIndex(resp[0], {
      replaceDefaultImg: true,
      index: runningIndex,
      replaceMap: softMap,
    })

    runningIndex++

    if (config?.relationEqpt) {
      await handleEqpt(item.eqptList, runningIndex, config.eqptTemplate)
    }
  }
  softMap.clear()
}

const handleScore = async (params: ProposalState) => {
  const { scoreData, insetPage, scoreTemplate, softwareTemplate, form } = params
  const scoreMap = new Map()
  const jsonPPTXForScore = ref<object | object[]>()

  if (scoreTemplate?.layoutId !== 0) {
    jsonPPTXForScore.value = await parsePPTistForJson(
      scoreTemplate?.layoutFileUrl,
    )
  }
  else {
    jsonPPTXForScore.value = genDefaultScoreLayout()
  }

  if (!scoreData) return

  const scoreList = scoreData.elementList || []

  const resp = handleCompatible(jsonPPTXForScore.value) as [Slide, Slide]

  /**
   * 页面1按照第一页布局排版，之后的页面按照第二页布局排版
   */

  // **补充空数据，保证至少 20 条,用于清空没有数据的字段**
  for (let i = 0; i < 20; i++) {
    scoreMap.set(getScoreFixedKey('要素名称', i), '')
    scoreMap.set(getScoreFixedKey('要素得分', i), '')
    scoreMap.set(getScoreFixedKey('要素得分分析', i), '')

    scoreMap.set(getScoreFixedKey('指标名称', i), '')
    scoreMap.set(getScoreFixedKey('指标得分', i), '')
    scoreMap.set(getScoreFixedKey('指标得分分析', i), '')

    scoreMap.set(getScoreFixedKey('痛点描述'), '')
  }

  // 第2页数据
  for (const scoreIndex in scoreList) {
    const index = parseInt(scoreIndex)
    const sData = scoreList[index]
    for (const targetIndex in sData.targetList) {
      let eReport = ''
      // 1、ai描述 2、原生 3、原生+ai描述
      switch (form?.descType) {
        case 2:
          eReport = sData.reportContent
          break
        case 1:
          eReport = `<span style="font-size: 16px;">${sData.aiAnalysisReport}</span>`
          break
        case 3:
          eReport = `${sData.reportContent}<span style="font-size: 16px;">${scoreData.aiAnalysisReport}</span>`
          break
        default:
          eReport = sData.reportContent
      }

      // 根据每个对象的数据重新赋值
      scoreMap.set(getScoreFixedKey('要素名称'), sData.name || '')
      scoreMap.set(getScoreFixedKey('要素得分'), sData.score || '')
      scoreMap.set(getScoreFixedKey('要素得分分析'), eReport)
      scoreMap.set(getScoreFixedKey('痛点描述'), sData.painPoint || '')

      const tarIndex = parseInt(targetIndex)
      const targetData = sData.targetList[tarIndex]

      let iReport = ''
      // 1、ai描述 2、原生 3、原生+ai描述
      switch (form?.descType) {
        case 2:
          iReport = targetData.reportContent
          break
        case 1:
          iReport = `<span style="font-size: 16px;">${targetData.aiAnalysisReport}</span>`
          break
        case 3:
          iReport = `${targetData.reportContent ?? ''}<span style="font-size: 16px;">${targetData.aiAnalysisReport}</span>`
          break
        default:
          iReport = targetData.reportContent
      }

      scoreMap.set(
        getScoreFixedKey('指标名称', tarIndex),
        targetData.name || '',
      )
      scoreMap.set(
        getScoreFixedKey('指标得分', tarIndex),
        targetData.score || '',
      )
      scoreMap.set(getScoreFixedKey('指标得分分析', tarIndex), iReport)
    }

    await insertSlideByIndex(resp[1], {
      index: insetPage + index,
      replaceMap: scoreMap,
      remark: sData.name, // 做标识，用于插入子系统
    })
  }

  // 第1页数据
  let tReport = ''
  // 1、ai描述 2、原生 3、原生+ai描述
  switch (form?.descType) {
    case 2:
      tReport = scoreData.reportContent
      break
    case 1:
      tReport = `<span style="font-size: 16px;">${scoreData.aiAnalysisReport}</span>`
      break
    case 3:
      tReport = `${scoreData.reportContent}<span style="font-size: 16px;">${scoreData.aiAnalysisReport}</span>`
      break
    default:
      tReport = scoreData.reportContent
  }
  scoreMap.set(getScoreFixedKey('总得分'), scoreData.totalScore || '')
  scoreMap.set(getScoreFixedKey('总得分分析'), tReport)

  scoreList.forEach((item: any, index: number) => {
    scoreMap.set(getScoreFixedKey('要素名称', index), item.name || '')
    scoreMap.set(getScoreFixedKey('要素得分', index), item.score || '')
  })
  await insertSlideByIndex(resp[0], {
    index: insetPage,
    replaceMap: scoreMap,
  })

  scoreMap.clear()

  // 插入评分页面下的子系统页面
  for await (const score of scoreList) {
    if (!score.proposalSystemList) continue

    const scoreDataIndex = slides.value.findIndex((item) => {
      return score.name === item.remark
    })

    await handleSoft(
      score.proposalSystemList,
      scoreDataIndex,
      softwareTemplate,
      {
        relationEqpt: true,
        eqptTemplate: params.eqptTemplate,
      },
    )
  }
}

const removeEmptySlide = () => {
  for (const slide of slides.value) {
    if (!slide.elements.length) {
      slidesStore.deleteSlide(slide.id)
    }
  }
}

const insertHeadPage = async (params: ProposalState) => {
  const headMap = new Map<string, string>([
    [getHeadFixedKey('项目图片'), params.coverImage ?? ''],
    [getHeadFixedKey('客户公司名称'), params.form?.companyName ?? ''],
    [getHeadFixedKey('提案公司名称'), params.form?.proposalCompanyName ?? ''],
    [getHeadFixedKey('提案名称'), params.form?.proposalName ?? ''],
    [getHeadFixedKey('日期'), params.form?.proposalTime ?? ''],
    [
      getHeadFixedKey('汇报人'),
      params.form?.saleName ? `汇报人：${params.form?.saleName}` : '',
    ],
    [
      getHeadFixedKey('部门'),
      params.form?.proposalDeptName ? `/${params.form?.proposalDeptName}` : '',
    ],
  ])
  if (params.form?.projectImg) {
    const result = hasProjectImageHeadSlice({
      projectImage: params.form?.projectImg,
    })

    insertSlideByIndex(result, {
      index: 0,
      replaceMap: headMap,
    })
    return
  }

  await insertSlideByIndex(defaultHeadPage(), {
    index: 0,
    replaceMap: headMap,
  })
}

const { createSlideByTemplate } = useSlideHandler()
const insertFootPage = async (quote: ProposalQuoteDetail) => {
  const result = getFootPage(quote)
  await createSlideByTemplate(result, -1)
}

onMounted(() => {
  window.addEventListener('message', handleReceiveMessage)
})

onBeforeUnmount(() => {
  window.removeEventListener('message', handleReceiveMessage)
})
</script>
